#pragma once

#include "Singleton.h"
#include "FrameWorker.h"
#include "Game/ServerService.h"
#include "Guild.h"

class GuildMgr : public FrameWorker, public AsyncTaskOwner,
	public WheelTimerOwner, public WheelRoutineType,
	public IServerService, public Singleton<GuildMgr>
{
public:
	THREAD_RUNTIME(GuildMgr)

	GuildMgr();
	virtual ~GuildMgr();

	virtual void Update(uint64 diffTime);
	virtual void OnTick();

	bool LoadDataFromDB();

	GErrorCode HandleGetGuildList(Coroutine::YieldContext& ctx, uint32 uid, uint32 startIndex, uint32 getCountMax);

	GErrorCode HandleGetGuildInfo(Coroutine::YieldContext& ctx, uint32 guildId, uint32 uid);
	GErrorCode HandleGetGuildMember(Coroutine::YieldContext& ctx, uint32 guildId, uint32 uid);
	GErrorCode HandleGetGuildApply(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId);

	GErrorCode HandleGuildInvite(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32 tgtGuildId, uint32 tgtPlayerId);
	GErrorCode HandleGuildInviteResp(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32 tgtGuildId, bool isAgree);
	GErrorCode HandleGuildApply(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32 tgtGuildId);
	GErrorCode HandleGuildApplyResp(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32 tgtGuildId, uint32 tgtApplicantId, bool isAgree);
	GErrorCode HandleGuildLeave(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId);
	GErrorCode HandleGuildKick(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32 tgtGuildId, uint32 tgtPlayerId);
	GErrorCode HandleGuildRise(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32 tgtGuildId, uint32 tgtPlayerId, int8 guildTitle);
	GErrorCode HandleGuildDisband(Coroutine::YieldContext& ctx, uint32 guildId, uint32 playerId, uint32& finalGuildId);

	GErrorCode HandleTryGuildCreate(uint32 guildId, uint32 playerId);
	GErrorCode HandleGuildCreate(uint32 gsId, uint32 guildId, uint32 playerId, uint32 newGuildId, const std::string_view& newGuildName);

	std::pair<Guild*, GuildMember*> GetGuildAndMemeber(uint32 playerId, uint32 guildId = 0) const;
	GuildMember* GetGuildMemeber(uint32 playerId, uint32 guildId = 0) const;
	Guild* GetGuild4Player(uint32 playerId, uint32 guildId = 0) const;
	Guild* GetGuild(uint32 guildId) const;

	void UpdateGuildRankData(const Guild* pGuild, int subType = -1);

	const std::unordered_map<uint32, Guild*>& GetGuilds() const { return m_guilds; }

	WheelTimerMgr sWheelTimerMgr;
	CBitMask sCharUpdateInfoBitMask;

private:
	void CreateGuild(uint32 gsId, uint32 playerId, uint32 guildId, const std::string_view& guildName);
	void DisbandGuild(Guild* pGuild, uint32 playerId);
	void AddGuildMember(Guild* pGuild, uint32 playerId, GUILD_JOIN_CAUSE cause);
	void RemoveGuildMember(Guild* pGuild, uint32 playerId, GUILD_QUIT_CAUSE cause);

	void UpdateGuildInformation(Guild* pGuild, bool isSync2Player = false);
	void UpdateGuildMember(Guild* pGuild, const GuildMember& guildMember, GUILD_JOIN_CAUSE cause);

	void PushPlayerJoinGuild(const GuildMember& guildMember, const Guild* pGuild, GUILD_JOIN_CAUSE cause);
	void PushPlayerQuitGuild(uint32 playerId, const Guild* pGuild, GUILD_QUIT_CAUSE cause);

	void RemoveInviteApplyRelation(uint32 playerId);
	void OnInviteRelationExpire(uint32 guildId, uint32 playerId);

	void SendPacket2AllGuildMemeber(const INetPacket& pck, const Guild* pGuild);
	void SendPacket2AllGuildMemeber(const INetPacket& pck, const Guild* pGuild, uint32 authorities);

	void PushAllGuildRankDatas();
	void NewGuildRankData(const Guild* pGuild);
	void RemoveGuildRankData(const Guild* pGuild);
	void PackGuildRankData(INetPacket& pck, const Guild* pGuild, RANK_SUBTYPE subType, int flags = 0);

	virtual int HandleClientPacket(uint32 uid, INetPacket& pck);
	virtual int HandleServerPacket(INetPacket& pck);

	virtual WheelTimerMgr *GetWheelTimerMgr();

	std::unordered_map<uint32, Guild*> m_guilds;

};

#define sGuildMgr (*GuildMgr::instance())
